package com.echartsdata.jwt;

import com.echartsdata.security.JwtTokenUtil;
import com.echartsdata.security.JwtUserDetailsService;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * JWT请求过滤器 - 用于拦截所有HTTP请求，验证JWT令牌并进行用户认证
 * 继承OncePerRequestFilter确保每个请求只被过滤一次
 * 核心职责：
 * 1. 从请求头中提取JWT令牌
 * 2. 验证令牌有效性
 * 3. 提取用户信息并进行身份认证
 * 4. 将认证信息存入SecurityContext，供后续流程使用
 */
@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService; // 用户详情服务，用于加载用户信息

    @Autowired
    private JwtTokenUtil jwtTokenUtil; // JWT工具类，用于令牌验证和解析

    /**
     * 过滤器核心方法，对每个HTTP请求进行处理
     * 1. 检查请求头中是否包含有效的JWT令牌
     * 2. 验证令牌并提取用户信息
     * 3. 进行用户认证并设置到SecurityContext中
     * 4. 异常处理：针对不同的认证异常返回相应的HTTP响应
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        final String requestTokenHeader = request.getHeader("Authorization"); // 获取请求头中的Authorization字段

        try {
            // 处理包含Bearer令牌的请求
            if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
                String jwtToken = requestTokenHeader.substring(7); // 提取JWT令牌（去掉"Bearer "前缀）
                /* validateTokenAndExtractUsername() 方法处理各种 JWT 异常情况：
                ExpiredJwtException：令牌过期
                SignatureException/MalformedJwtException：签名错误或格式错误
                IllegalArgumentException：参数非法（如令牌为空）
                验证令牌并提取用户名**/
                String username = validateTokenAndExtractUsername(jwtToken);

                // 如果用户名存在且当前上下文未认证，则进行用户认证
                if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    authenticateUser(username, jwtToken, request);
                }
            }

            // 继续执行后续过滤器链
            chain.doFilter(request, response);

        } catch (AuthenticationException e) {
            // 认证异常处理：清除安全上下文，返回401未授权响应
            SecurityContextHolder.clearContext();
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"error\":\"" + e.getMessage() + "\"}");
            return; // 终止请求处理流程

        } catch (Exception e) {
            // 其他异常处理：记录错误日志，返回500内部错误
            logger.error("Filter processing error", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            chain.doFilter(request, response);
        }
    }

    /**
     * 验证JWT令牌并提取用户名
     * @param jwtToken JWT令牌字符串
     * @return 令牌中包含的用户名（如果验证通过）
     * @throws AuthenticationException 令牌验证失败时抛出的异常
     */
    private String validateTokenAndExtractUsername(String jwtToken) throws AuthenticationException {
        try {
            // 调用JwtTokenUtil提取用户名（内部包含签名验证和过期检查）
            return jwtTokenUtil.extractUsername(jwtToken);
        } catch (ExpiredJwtException e) {
            // 令牌过期异常
            throw new AuthenticationServiceException("令牌已过期", e);
        } catch (SignatureException | MalformedJwtException e) {
            // 签名错误或令牌格式错误
            throw new BadCredentialsException("无效的令牌", e);
        } catch (IllegalArgumentException e) {
            // 参数非法（如令牌为空）
            throw new AuthenticationServiceException("无法获取令牌", e);
        } catch (Exception e) {
            // 其他验证异常
            throw new AuthenticationServiceException("令牌验证失败", e);
        }
    }

    /**
     * 根据用户名和JWT令牌进行用户认证
     * @param username 用户名
     * @param jwtToken JWT令牌
     * @param request  HTTP请求对象
     */
    private void authenticateUser(String username, String jwtToken, HttpServletRequest request) {
        // 从数据库加载用户详情
        UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(username);

        // 验证令牌与用户信息是否匹配
        if (!jwtTokenUtil.validateToken(jwtToken, userDetails)) {
            throw new BadCredentialsException("无效的JWT令牌");
        }

        // 创建认证对象
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                userDetails, null, userDetails.getAuthorities());

        // 设置请求详情（如IP地址、Session信息等）
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

        // 将认证信息存入SecurityContext，供后续流程使用
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
}